package com.xmim.core.session;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class DefaultSessionPipeline implements SessionPipeline {
    private Session session;
    DefaultSessionHandlerContext head;

    public DefaultSessionPipeline(Session session) {
        this.session = session;
        this.head = new DefaultSessionHandlerContext(this, this.getClass().getName(), new SessionHandle() {
        });
    }

    @Override
    public SessionPipeline add(String name, SessionHandle handler) {
        DefaultSessionHandlerContext context = head;
        while (context.next != null) {
            context = context.next;
        }
        context.next = new DefaultSessionHandlerContext(this, name, handler);
        return this;
    }

    @Override
    public SessionPipeline add(SessionHandle... handlers) {
        for (SessionHandle handler : handlers) {
            this.add(handler.getClass().getName(), handler);
        }
        return this;
    }

    @Override
    public SessionPipeline remove(SessionHandle handler) {
        DefaultSessionHandlerContext next = head;
        DefaultSessionHandlerContext before = null;
        while (next.next != null) {
            before = next;
            next = next.next;
            if (handler.equals(next.handler)) {
                before.next = null;
                before.next = next.next;
            }
        }
        return this;
    }

    @Override
    public SessionHandle remove(String name) {
        DefaultSessionHandlerContext next = head;
        DefaultSessionHandlerContext before = head;
        while (next.next != null) {
            before = next;
            next = next.next;
            if (name.equals(next.name)) {
                SessionHandle handler = next.handler;
                before.next = null;
                before.next = next.next;
                return handler;
            }
        }
        return null;
    }

    @Override
    public <T extends SessionHandle> T remove(Class<T> handlerType) {
        DefaultSessionHandlerContext next = head;
        DefaultSessionHandlerContext before = null;
        while (next.next != null) {
            before = next;
            next = next.next;
            if (handlerType.equals(next.handler.getClass())) {
                SessionHandle handler = next.handler;
                before.next = null;
                before.next = next.next;
                return (T) handler;
            }
        }
        return null;
    }


    @Override
    public SessionHandle get(String name) {
        DefaultSessionHandlerContext next = head;
        while (next.next != null) {
            next = next.next;
            if (name.equals(next.name)) {
                return next.handler;
            }
        }
        return null;
    }

    @Override
    public <T extends SessionHandle> T get(Class<T> handlerType) {
        DefaultSessionHandlerContext next = head;
        while (next.next != null) {
            next = next.next;
            if (handlerType.equals(next.handler.getClass())) {
                return (T) next.handler;
            }
        }
        return null;
    }

    @Override
    public SessionHandleContext context(SessionHandle handler) {
        DefaultSessionHandlerContext next = head;
        while (next.next != null) {
            next = next.next;
            if (handler.equals(next.handler)) {
                return next;
            }
        }
        return null;
    }

    @Override
    public SessionHandleContext context(String name) {
        DefaultSessionHandlerContext next = head;
        while (next.next != null) {
            next = next.next;
            if (name.equals(next.name)) {
                return next;
            }
        }
        return null;
    }

    @Override
    public SessionHandleContext context(Class<? extends SessionHandle> handlerType) {
        DefaultSessionHandlerContext next = head;
        while (next.next != null) {
            next = next.next;
            if (handlerType.equals(next.handler.getClass())) {
                return next;
            }
        }
        return null;
    }

    @Override
    public Session session() {
        return session;
    }


    @Override
    public final List<String> names() {
        List<String> list = new ArrayList<String>();
        DefaultSessionHandlerContext ctx = head.next;
        for (; ; ) {
            if (ctx == null) {
                return list;
            }
            list.add(ctx.name());
            ctx = ctx.next;
        }
    }

    @Override
    public final Map<String, SessionHandle> toMap() {
        Map<String, SessionHandle> map = new LinkedHashMap<String, SessionHandle>();
        DefaultSessionHandlerContext ctx = head.next;
        for (; ; ) {
            if (ctx == null) {
                return map;
            }
            map.put(ctx.name(), ctx.handler());
            ctx = ctx.next;
        }
    }

    @Override
    public String name() {
        return head.name;
    }

    @Override
    public SessionHandle handler() {
        return head.handler;
    }

    @Override
    public SessionPipeline pipeline() {
        return head.pipeline;
    }

    @Override
    public void fireAdded() throws Exception {
        DefaultSessionHandlerContext.invokeAdded(head);
    }

    @Override
    public void fireRemoved() throws Exception {
        DefaultSessionHandlerContext.invokeRemoved(head);
    }

    @Override
    public void fireRead(Object msg) throws Exception {
        DefaultSessionHandlerContext.invokeRead(head, msg);
    }

    @Override
    public void fireClose() throws Exception {
        DefaultSessionHandlerContext.invokeClose(head);
    }

    @Override
    public void fireHeartbeat(Object msg) throws Exception {
        DefaultSessionHandlerContext.invokeHeartbeat(head, msg);
    }

    @Override
    public void fireException(Throwable cause) throws Exception {
        DefaultSessionHandlerContext.invokeException(head, cause);
    }

    @Override
    public void fireReadComplete() throws Exception {
        DefaultSessionHandlerContext.invokeReadComplete(head);
    }

    @Override
    public void fireWriteComplete() throws Exception {
        DefaultSessionHandlerContext.invokeWriteComplete(head);
    }
}
